from datetime import datetime
from typing_extensions import Annotated, List
from fastapi import Depends, Request, HTTPException
from sqlalchemy import func, select, Select

from core.models import Board, BoardNew
from core.database import db_session
from core.exception import AlertException
from lib.common import dynamic_create_write_table, cut_name, FileCache
from lib.board_lib import BoardConfig, get_list, get_list_thumbnail
from service import BaseService
from service.ajax.ajax import AJAXService
from service.board_file_service import BoardFileService
from service.point_service import PointService
from api.v1.service.member import MemberImageServiceAPI


class BoardNewService(BaseService):
    """
  最新帖子管理类（查看和删除最新帖子列表等）
    """
    def __init__(
        self,
        request: Request,
        db: db_session,
        file_service: Annotated[BoardFileService, Depends()],
        point_service: Annotated[PointService, Depends()],
    ):
        self.request = request
        self.db = db
        self.config = request.state.config
        self.page_rows = self.config.cf_mobile_page_rows if request.state.is_mobile and self.config.cf_mobile_page_rows else self.config.cf_new_rows
        self.file_service = file_service
        self.point_service = point_service

    @classmethod
    async def async_init(
        cls,
        request: Request,
        db: db_session,
        file_service: Annotated[BoardFileService, Depends()],
        point_service: Annotated[PointService, Depends()],
    ):
        instance = cls(request, db, file_service, point_service)
        return instance

    def raise_exception(self, status_code: int, detail: str = None):
        raise AlertException(status_code=status_code, detail=detail)

    def format_datetime(self, wr_datetime: datetime) -> str:
        """
        时间显示如果是同一天
        """
        current_datetime = datetime.now()

        if wr_datetime.date() == current_datetime.date():
            return wr_datetime.strftime("%H:%M")
        else:
            return wr_datetime.strftime("%y-%m-%d")

    def get_query(
            self, gr_id: str = None, mb_id: str = None, view: str = None
    ) -> Select:
        """根据搜索条件返回query"""
        query = select().join(BoardNew.board).order_by(BoardNew.bn_id.desc())

        if gr_id:
            query = query.where(Board.gr_id == gr_id)
        if mb_id:
            query = query.where(BoardNew.mb_id == mb_id)
        if view == "write":
            query = query.where(BoardNew.wr_parent == BoardNew.wr_id)
        elif view == "comment":
            query = query.where(BoardNew.wr_parent != BoardNew.wr_id)
        return query

    def get_offset(self, current_page: int) -> int:
        """用于页面计算 offset 设置"""
        offset = (current_page - 1) * self.page_rows
        return offset

    def get_board_news(self, query: Select, offset: int, per_page: int = None) -> List[BoardNew]:
        """查看最新文章列表"""
        per_page = per_page or self.page_rows
        board_news = self.db.scalars(query.add_columns(BoardNew).offset(offset).limit(per_page)).all()
        return board_news

    def get_total_count(self, query: Select) -> int:
        """最新职位总数"""
        total_count = self.db.scalar(query.add_columns(func.count(BoardNew.bn_id)).order_by(None))
        return total_count

    def arrange_borad_news_data(self, board_news: List[BoardNew], total_count: int, offset: int):
        """设置最新结果数据"""
        for new in board_news:
            new.num = total_count - offset - (board_news.index((new)))
            # 岗位信息查询
            write_model = dynamic_create_write_table(new.bo_table)
            write = self.db.get(write_model, new.wr_id)
            if write:
                # 评论/按职位分隔
                if write.wr_is_comment:
                    new.subject = "[评论] " + write.wr_content[:100]
                    new.link = f"/board/{new.bo_table}/{new.wr_parent}#c_{write.wr_id}"
                else:
                    new.subject = write.wr_subject
                    new.link = f"/board/{new.bo_table}/{new.wr_id}"

                #作者
                new.name = cut_name(self.request, write.wr_name)
                # 时间设置
                new.datetime = self.format_datetime(write.wr_datetime)

    def get_latest_posts(
        self,
        bo_table_list: List[str], view_type: str = "write",
        rows: int = 10, subject_len: int = 40
    ):
        """打印最新文章列表"""
        request = self.request
        db = self.db
        boards_info = dict()
        for bo_table in bo_table_list:
            board = db.get(Board, bo_table)
            if not board:
                self.raise_exception(
                    status_code=400, detail=f"{bo_table} 无公告板信息."
                )
            board_config = BoardConfig(request, board)
            board.subject = board_config.subject

            #帖子查询列表
            write_model = dynamic_create_write_table(bo_table)
            query = select(write_model).order_by(write_model.wr_num).limit(rows)
            if view_type == "comment":
                query = query.where(write_model.wr_is_comment == 1)
            else:
                query = query.where(write_model.wr_is_comment == 0)
            writes = db.scalars(query).all()

            for write in writes:
                write = get_list(request, db, write, board_config, subject_len)
                # 查看附件信息
                write.images, write.normal_files = self.file_service.get_board_files_by_type(bo_table, write.wr_id)
                # 设置缩略图图像
                write.thumbnail = get_list_thumbnail(request, board, write, board_config.gallery_width, board_config.gallery_height)

                # 会员图像，设置图标路径
                write.mb_image_path = MemberImageServiceAPI.get_image_path(write.mb_id)
                write.mb_icon_path = MemberImageServiceAPI.get_icon_path(write.mb_id)

                # 帖子设置为“好/不好”
                ajax_good_data = AJAXService(self.request, self.db).get_ajax_good_data(bo_table, write)
                write.good = ajax_good_data["good"]
                write.nogood = ajax_good_data["nogood"]

            boards_info[bo_table] = writes

        return boards_info

    def delete_board_news(self, bn_ids: list):
        """删除最新帖子"""
        # 新文章信息查询
        board_news = self.db.scalars(select(BoardNew).where(BoardNew.bn_id.in_(bn_ids))).all()
        for new in board_news:
            board = self.db.get(Board, new.bo_table)
            write_model = dynamic_create_write_table(new.bo_table)
            write = self.db.get(write_model, new.wr_id)
            if write:
                if write.wr_is_comment == 0:
                    # 删除帖子
                    # TODO: 删除帖子添加常用功能
                    self.db.delete(write)

                    # 删除单字母点
                    if not self.point_service.delete_point(write.mb_id, board.bo_table, write.wr_id, "写作"):
                        self.point_service.save_point(write.mb_id, board.bo_write_point * (-1),
                                                      f"{board.bo_subject} {write.wr_id} 删除帖子")
                else:
                    # 删除评论
                    # TODO: 删除注释添加常用功能
                    self.db.delete(write)

                    # 删除评论点
                    if not self.point_service.delete_point(write.mb_id, board.bo_table, write.wr_id, "评论"):
                        self.point_service.save_point(write.mb_id, board.bo_comment_point * (-1),
                                                      f"{board.bo_subject} {write.wr_parent}-{write.wr_id} 删除评论")
                # 删除文件
                self.file_service.delete_board_files(board.bo_table, write.wr_id)

            # 删除最新帖子
            self.db.delete(new)

            # 删除最新的post缓存
            FileCache().delete_prefix(f'latest-{new.bo_table}')

        self.db.commit()


class BoardNewServiceAPI(BoardNewService):
    """
    API 用于请求类的最新帖子列表
    - 这个类是 API我们通过过度驱动实现与相关的特定异常处理.
    """

    def raise_exception(self, status_code: int, detail: str = None):
        raise HTTPException(status_code=status_code, detail=detail)
